library Summon initializer Init requires utils

    /*
    --------------------------------------------------------------------------
    # SummonUnit
    --------------------------------------------------------------------------
    * param 
    */
    struct SummonUnit extends array
        unit m_unit
        unit m_owner
        real m_duration

        method isNull takes nothing returns boolean
            return this.m_unit == null
        endmethod

        static method get takes unit u returns thistype
            return thistype(Unit.get(u))
        endmethod

        static method create takes unit u returns thistype
            local thistype this = thistype.get(u)
            if not this.isNull() then
                return this
            endif

            set this.m_unit = u
            set this.m_duration = 0.00

            debug call BJDebugMsg("summonUnit create : " + GetUnitName(u))

            return this
        endmethod

        method destroy takes nothing returns nothing
            set this.m_unit = null
            set this.m_owner = null
        endmethod

        method setOwner takes unit u returns nothing
            set this.m_owner = u
        endmethod

    endstruct

    /*
    --------------------------------------------------------------------------
    # 召唤
    --------------------------------------------------------------------------
    * param 
    */
    struct Summon
        //召唤者
        unit m_owner
        //召唤单位类型
        integer m_summonUnitType
        //召唤数量限制
        integer m_limit
        //被召唤者列表
        List m_summonUnits

        //当前召唤数量
        private integer m_counts

        implement StructList

        static method get takes unit ud, integer summonUnitType returns thistype
            local thistype d = thistype.first
            loop
                exitwhen (d <= 0)
                if d.m_owner == ud and d.m_summonUnitType == summonUnitType then
                    return d
                endif
                set d = d.next
            endloop
            return 0
        endmethod

        static method create takes unit ud, integer summonUnitType returns thistype
            local thistype this = thistype.get(ud, summonUnitType)
            if this > 0 then
                return this
            endif
            set this = thistype.allocate()
            set this.m_owner = ud
            set this.m_summonUnitType = summonUnitType
            set this.m_summonUnits = List.create()
            set this.m_counts = 0
            set this.m_limit = 999

            call this.listAdd()

            debug call BJDebugMsg("create Summon : " + I2S(this) +" ud :"+GetUnitName(ud.m_owner)+"summonUnitType :"+I2S(summonUnitType))

            return this
        endmethod

        method destroy takes nothing returns nothing
            call this.m_summonUnits.destroy()

            set this.m_owner = null
            call this.listRemove()
            call this.deallocate()
        endmethod

        method remove takes SummonUnit smud returns nothing
            local Link link = this.m_summonUnits.search(smud)
            if link != 0 then
                set this.m_counts = this.m_counts - 1
                call smud.destroy()
                call link.destroy()

                debug call BJDebugMsg("remove SummonUnit : " + I2S(this) +" ud :"+GetUnitName(smud.m_unit))
            endif
        endmethod

        method add takes SummonUnit smud returns nothing
            local Link link = this.m_summonUnits.first
            local SummonUnit first = SummonUnit(link.data)

            if this.m_limit != 0 and this.m_counts >= this.m_limit then
                call KillUnit(first.m_unit)
                call this.remove(first)
            endif

            call Link.create(this.m_summonUnits, smud)
            set this.m_counts = this.m_counts + 1
        endmethod

        method summonUnitFromExist takes unit u returns nothing
            local SummonUnit smud = SummonUnit.create(u)
            
            call smud.setOwner(this.m_owner)
            call this.add(smud)
        endmethod

        method summonUnit takes integer unitId, real x, real y, real ang returns unit
            local unit u = CreateUnit(GetOwningPlayer(this.m_owner), unitId, x, y, ang)
            call this.summonUnitFromExist(u)
            return u
        endmethod

    endstruct


    private function SummonUnitDeath takes unit u returns nothing
        local SummonUnit smud = SummonUnit.get(u)
        local Summon sm

        if not smud.isNull() then
            debug call BJDebugMsg("summonUnitDeath : " + GetUnitName(u))

            set sm = Summon.get(smud.m_owner, GetUnitTypeId(u))
            call sm.remove(smud)
        endif
    endfunction

    private function Init takes nothing returns nothing
        call RegisterUnitDeathResponse(SummonUnitDeath)
    endfunction

endlibrary
